﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;

namespace Sudoku
{
    public partial class SudokuForma : Form
    {
        bool nonNumberEntered = false;
        bool humanTextChange = false;
        bool gotovaIgra = false, pocelaIgra = false;
        Stopwatch štoperica = new Stopwatch();
        String level, stanjeStatusneLabele;
        List<Rekord> rekordi = new List<Rekord>();
        SquareBox tabla;
        CompositeBox combox = new CompositeBox();
        SudokuBoardBuilder bilder = new SudokuBoardBuilder(); 
        int brojPocetnih = 0, brojUnesenih = 0;
        bool validiran = false;
        public SudokuForma()
        {
            InitializeComponent();
            this.timer1.Tick += new EventHandler(timer_tick);
            this.timer1.Interval = (1000) * (1);
            this.labelStatus.Text = "Započnite igru";
            this.stanjeStatusneLabele = "Level: " + level + " - igra u toku.";

            //Dodjela različitih događaja textboxovima
            foreach(Panel p in panelGlavni.Controls)
                foreach(RichTextBox t in p.Controls)
                {
                    t.SelectionAlignment = HorizontalAlignment.Center;
                    t.Enabled = false;
                    t.Font = new System.Drawing.Font("Microsoft Sans Serif", 25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
                    t.Enter += new System.EventHandler(this.polje_Enter);
                    t.KeyDown += new System.Windows.Forms.KeyEventHandler(this.polje_KeyDown);
                    t.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.polje_KeyPress);
                    t.Leave += new System.EventHandler(this.polje_Leave);
                    t.TextChanged += new EventHandler(this.polje_Text_Changed);
                }
            this.ucitajRekorde();
            //for(int i = 0; i < 9; i++)
                //for(int j = 0; j < 9; j++)
                //{
                    //String tmp = Convert.ToString(i+1) + Convert.ToString(j+1);
                    //tabla.combox[i].Boxes[j].Txt = this.vratiTextBox(tmp[0], tmp[1]);
                //}
            //this.popuniTabelu(4, 7);
        }
        public void popuniTabelu(int inside, int outside = 9)
        {
            bilder.CreateSudokuBoard(9);
            DAL.DAL d = DAL.DAL.Instanca;
            d.kreirajKonekciju("127.0.0.1", "sudoku", "root", "");
            DAL.DAL.SquareBoxDAO tDao = new DAL.DAL.SquareBoxDAO();
            this.tabla = tDao.getById(1);
            d.terminirajKonekciju();

            this.tabla.popuniTablu();
            int x, y;

            this.ocistiPlocu();
            if (!štoperica.IsRunning && štoperica.Elapsed.Milliseconds != 0)
                štoperica.Restart();
            foreach (Panel p in panelGlavni.Controls)
                foreach (RichTextBox r in p.Controls)
                {
                    r.Enabled = true;
                    r.ReadOnly = false;
                    r.BackColor = Color.White;
                }
            gotovaIgra = false;
            pocelaIgra = true;
            humanTextChange = false;
            brojUnesenih = 0;
            brojPocetnih = inside * outside;

            Random rand = new Random();
            
            List<Int32> vanjski = new List<Int32>();
            for (Int32 i = 0; i < outside; i++)
            {
                Int32 curValue = rand.Next(1, 10);
                while (vanjski.Exists(value => value == curValue))
                {
                    curValue = rand.Next(1, 10);
                }
                vanjski.Add(curValue);
            }
            List<Int32> unutarnji = new List<Int32>();
                
            for(int i = 0; i < outside; i++)
            {
                unutarnji.Clear();
                for (Int32 count = 0; count < inside; count++)
                {
                    Int32 curValue = rand.Next(1, 10);
                    while (unutarnji.Exists(value => value == curValue))
                    {
                        curValue = rand.Next(1, 10);
                    }
                    unutarnji.Add(curValue);
                } 

                x = vanjski[i];
                for(int j = 0; j < inside; j++)
                {
                    y = unutarnji[j];
                    String tmp = Convert.ToString(x) + Convert.ToString(y);
                    RichTextBox txt = this.vratiTextBox(tmp[0], tmp[1]);
                    
                    txt.ReadOnly = true;
                    //txt.Enabled = false;
                    txt.BackColor = System.Drawing.SystemColors.GradientInactiveCaption;
                    txt.Text = this.tabla.tabla[x - 1][y - 1].ToString();
                }
            }
            brojUnesenih = 0;
            humanTextChange = true;
        }

        private void ucitajRekorde()
        {
            DAL.DAL dal = DAL.DAL.Instanca;
            dal.kreirajKonekciju("127.0.0.1", "sudoku", "root", "");
            DAL.DAL.RekordDAO d = new DAL.DAL.RekordDAO();
            rekordi = d.getAll();
            dal.terminirajKonekciju();
            int i = 1;
            String naziv, time;
            foreach (Rekord r in rekordi)
            {
                naziv = (r.Ime + " " + r.Prezime);
                if (naziv.Length > 20)
                    naziv = naziv.Substring(0, 20);
                naziv = naziv.PadRight(20);
                time = Convert.ToString((int)(r.Vrijeme / 60)).PadLeft(2, '0') + ":" + Convert.ToString(r.Vrijeme % 60).PadLeft(2, '0');
                this.rekordiDropDownButton.DropDownItems.Add(Convert.ToString(i) + ". " + naziv + r.Datum.ToShortDateString() + " - " + time + "  (" + r.Level + ")");
                i++;
            }
        }
        
        public void spremiRekord()
        {
            SpremanjeRekordaForma srf = new SpremanjeRekordaForma(rekordi[4].Id, this.štoperica.Elapsed.Minutes*60+this.štoperica.Elapsed.Seconds, this.level);
            srf.ShowDialog();
            rekordi.Clear();
            this.rekordiDropDownButton.DropDownItems.Clear();
            ucitajRekorde();
        }

        #region RazličitiEventi
        //Event za timer koji se poziva prilikom svako otkucaja timera
        private void timer_tick(object sender, EventArgs e)
        {
            this.labelVrijeme.Text = "Vrijeme: " + Convert.ToString(štoperica.Elapsed.Minutes).PadLeft(2, '0') + ":" + 
                Convert.ToString(štoperica.Elapsed.Seconds).PadLeft(2, '0');
        }
        //Event za registrovanje stisnute tipke, korišten za zabranu 
        //unošenja bilo čega osim broja u rich textboxe
        private void polje_KeyDown(object sender, KeyEventArgs e)
        {
            // Initialize the flag to false.
            nonNumberEntered = false;
            // Determine whether the keystroke is a number from the top of the keyboard. 
            if (e.KeyCode < Keys.D0 || e.KeyCode > Keys.D9)
            {
                // Determine whether the keystroke is a number from the keypad. 
                if (e.KeyCode < Keys.NumPad0 || e.KeyCode > Keys.NumPad9)
                {
                    // Determine whether the keystroke is a backspace. 
                    if (e.KeyCode != Keys.Back)
                    {
                        // A non-numerical keystroke was pressed. 
                        // Set the flag to true and evaluate in KeyPress event.
                        nonNumberEntered = true;
                    }
                   
                }
            }
            //If shift key was pressed, it's not a number. 
            if (Control.ModifierKeys == Keys.Shift)
            {
                nonNumberEntered = true;
            }

            String txt = (sender as RichTextBox).Name;
            char indeks1 = txt[txt.Length - 3];
            char indeks2 = txt[txt.Length - 1];

            if(e.KeyCode == Keys.Enter)
            {
                e.SuppressKeyPress = true;
                return;
            }
            if(e.KeyCode == Keys.Left)
            {
                e.SuppressKeyPress = true;
                pomjeriKursorLijevo(indeks1, indeks2);
            }
            else if(e.KeyCode == Keys.Right)
            {
                e.SuppressKeyPress = true;
                pomjeriKursorDesno(indeks1, indeks2);
            }
            else if(e.KeyCode == Keys.Up)
            {
                e.SuppressKeyPress = true;
                pomjeriKursorGore(indeks1, indeks2);
            }
            else if(e.KeyCode == Keys.Down)
            {
                e.SuppressKeyPress = true;
                pomjeriKursorDole(indeks1, indeks2);
            }
            RichTextBox rich = sender as RichTextBox;
            if (rich.Text.Length == 1)
            {
                nonNumberEntered = true;
                return;
            }
        }
        //Event za pritisak tipke, realizuje zabranu unosa karaktera
        private void polje_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (this.nonNumberEntered)
                e.Handled = true;
        }
        //Event za promjenu boje textboxa prilikom ulaska
        private void polje_Enter(object sender, EventArgs e)
        {
            //Promijeni boju
            
            RichTextBox r = sender as RichTextBox;
            if (r.ReadOnly)
                return;
            r.BackColor = System.Drawing.Color.LightSkyBlue;

        }
        //Event za promjenu boje textboxa prilikom izlaska
        private void polje_Leave(object sender, EventArgs e)
        {
            //Vrati boju
            RichTextBox r = sender as RichTextBox;
            if (r.ReadOnly)
                return;
            r.BackColor = System.Drawing.SystemColors.Window;
        }
        //Event za sve textboxe Text Changed
        private void polje_Text_Changed(object sender, EventArgs e)
        {
            RichTextBox rt = sender as RichTextBox;
            int m, n;
            m = Convert.ToInt32(rt.Name[rt.Name.Length-3]);
            n = Convert.ToInt32(rt.Name[rt.Name.Length-1]);
            //this.tabla.combox[m].Boxes[n].EnteredDigit = Convert.ToInt32(rt.Text);
            if (rt.Text == "")
                brojUnesenih--;
            else
                brojUnesenih++;
            if (humanTextChange && (brojUnesenih + brojPocetnih) == 81)
                validacija();
            if (validiran)
                vratiBoje();
        }
#endregion
        private void krajIgreToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }


        #region FunkcijeZaKretanjeKursora
        private void pomjeriKursorDole(char i1, char i2)
        {
            if ((i1 == '7' || i1 == '8' || i1 == '9') && (i2 == '7' || i2 == '8' || i2 == '9'))
                return;
            else if (i2 == '7' || i2 == '8' || i2 == '9')
            {
                i1 = Convert.ToChar(Convert.ToInt32(i1) + 3);
                i2 = Convert.ToChar(Convert.ToInt32(i2) - 6);
            }
            else
            {
                i2 = Convert.ToChar(Convert.ToInt32(i2) + 3);
            }
            RichTextBox tmp = vratiTextBox(i1, i2);
            tmp.Focus();
        }

        private void pomjeriKursorGore(char i1, char i2)
        {
            if ((i1 == '1' || i1 == '2' || i1 == '3') && (i2 == '1' || i2 == '2' || i2 == '3'))
                return;
            else if (i2 == '1' || i2 == '2' || i2 == '3')
            {
                i1 = Convert.ToChar(Convert.ToInt32(i1) - 3);
                i2 = Convert.ToChar(Convert.ToInt32(i2) + 6);
            }
            else
            {
                i2 = Convert.ToChar(Convert.ToInt32(i2) - 3);
            }
            RichTextBox tmp = vratiTextBox(i1, i2);
            tmp.Focus();
        }

        private void pomjeriKursorDesno(char i1, char i2)
        {
            if ((i1 == '3' || i1 == '6' || i1 == '9') && (i2 == '3' || i2 == '6' || i2 == '9'))
                return;
            else if (i2 == '3' || i2 == '6' || i2 == '9')
            {
                i1 = Convert.ToChar(Convert.ToInt32(i1) + 1);
                i2 = Convert.ToChar(Convert.ToInt32(i2) - 2);
            }
            else
            {
                i2 = Convert.ToChar(Convert.ToInt32(i2) + 1);
            }
            RichTextBox tmp = vratiTextBox(i1, i2);
            tmp.Focus();
        }

        private void pomjeriKursorLijevo(char i1, char i2)
        {
            if ((i1 == '1' || i1 == '4' || i1 == '7') && (i2 == '1' || i2 == '4' || i2 == '7'))
                return;
            else if(i2 == '1' || i2 == '4' || i2 == '7')
            {
                i1 = Convert.ToChar(Convert.ToInt32(i1) - 1);
                i2 = Convert.ToChar(Convert.ToInt32(i2) + 2);
            }
            else
            {
                i2 = Convert.ToChar(Convert.ToInt32(i2) - 1);
            }
            RichTextBox tmp = vratiTextBox(i1, i2);
            tmp.Focus();
        }
        #endregion

        #region EventiZaKlikPrilikomOdabiraLevela
        private void levelBegginerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if(štoperica.IsRunning)
            {
                štoperica.Stop();
                DialogResult dialogResult = MessageBox.Show("Dali ste sigurni ?", "Igra u toku", MessageBoxButtons.YesNo);
                if (dialogResult == DialogResult.Yes)
                {
                    this.štoperica.Reset();
                }
                else if (dialogResult == DialogResult.No)
                {
                    štoperica.Start();
                    return;
                }   
            }
            //this.bilder.NewGame(0);
            this.popuniTabelu(8);
            this.timer1.Enabled = true;
            this.timer1.Start();
            this.štoperica.Start();
            level = "Beginner";
            this.labelStatus.Text = "Level: " + level + " - igra u toku.";
        }

        private void levelAmateurToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (štoperica.IsRunning)
            {
                štoperica.Stop();
                DialogResult dialogResult = MessageBox.Show("Dali ste sigurni ?", "Igra u toku", MessageBoxButtons.YesNo);
                if (dialogResult == DialogResult.Yes)
                {
                    this.štoperica.Reset();
                }
                else if (dialogResult == DialogResult.No)
                {
                    štoperica.Start();
                    return;
                }
            }
            //this.bilder.NewGame(1);
            this.popuniTabelu(6);
            this.timer1.Enabled = true;
            this.timer1.Start();
            this.štoperica.Start();
            level = "Amateur";
            this.labelStatus.Text = "Level: " + level + " - igra u toku.";
        }

        private void levelProffeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (štoperica.IsRunning)
            {
                štoperica.Stop();
                DialogResult dialogResult = MessageBox.Show("Dali ste sigurni ?", "Igra u toku", MessageBoxButtons.YesNo);
                if (dialogResult == DialogResult.Yes)
                {
                    this.štoperica.Reset();
                }
                else if (dialogResult == DialogResult.No)
                {
                    štoperica.Start();
                    return;
                }
            }
            //this.bilder.NewGame(2);
            this.popuniTabelu(4, 6);
            this.timer1.Enabled = true;
            this.timer1.Start();
            this.štoperica.Start();
            level = "Professional";
            this.labelStatus.Text = "Level: " + level + " - igra u toku.";
        }

        private void levelMasterToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (štoperica.IsRunning)
            {
                štoperica.Stop();
                DialogResult dialogResult = MessageBox.Show("Dali ste sigurni ?", "Igra u toku", MessageBoxButtons.YesNo);
                if (dialogResult == DialogResult.Yes)
                {
                    this.štoperica.Reset();
                }
                else if (dialogResult == DialogResult.No)
                {
                    štoperica.Start();
                    return;
                }
            }
            //this.bilder.NewGame(3);
            this.popuniTabelu(3, 4);
            this.timer1.Enabled = true;
            this.timer1.Start();
            this.štoperica.Start();
            level = "Master";
            this.labelStatus.Text = "Level: " + level + " - igra u toku.";
        }
        #endregion
       
        private void prekiniIgruToolStripMenuItem_Click(object sender, EventArgs e)
        {
            pauziraj();
        }

        private void pauziraj()
        {
            if (gotovaIgra || !pocelaIgra)
                return;
            if (this.prekiniIgruToolStripMenuItem.Text == "Zaustavi igru")
            {
                this.prekiniIgruToolStripMenuItem.Text = "Nastavi igru";
                štoperica.Stop();
                this.labelStatus.Text = "Igra zaustavljena.";
                foreach (Panel p in this.panelGlavni.Controls)
                    foreach (RichTextBox r in p.Controls)
                        r.Enabled = false;
            }
            else
            {
                this.prekiniIgruToolStripMenuItem.Text = "Zaustavi igru";
                štoperica.Start();
                this.labelStatus.Text = "Level: " + level + " - igra u toku.";
                foreach (Panel p in this.panelGlavni.Controls)
                    foreach (RichTextBox r in p.Controls)
                        r.Enabled = true;
                this.vratiTextBox('1', '1').Focus();
            }
        }
        private void btnValidacija_Click(object sender, EventArgs e)
        {
            validiran = true;
            provjeriRješenja();
        }
        RichTextBox vratiTextBox(char indeks1, char indeks2)
        {
            foreach (Panel p in this.panelGlavni.Controls)
                foreach (RichTextBox t in p.Controls)
                    if (t.Name[t.Name.Length - 3] == indeks1 && t.Name[t.Name.Length - 1] == indeks2)
                        return t;
            return new RichTextBox();
        }
        public void provjeriRješenja()
        {
            bool greska = false;
            for(int i = 0; i < 9; i++)
                for(int j = 0; j < 9; j++)
                {
                    String tmp = Convert.ToString(i + 1) + Convert.ToString(j + 1);
                    RichTextBox rchtxt = vratiTextBox(tmp[0], tmp[1]);
                    //MessageBox.Show(rchtxt.Text);
                    if(rchtxt.Enabled && rchtxt.Text != "")
                        if (rchtxt.Text != this.tabla.tabla[i][j].ToString())
                        {
                            rchtxt.BackColor = Color.OrangeRed;
                            greska = true;
                        }
                }
            if(greska)
            {
                this.stanjeStatusneLabele = labelStatus.Text;
                this.SudokuStatusStrip.BackColor = Color.OrangeRed;
                this.labelStatus.Text = "Sudoku nije ispravno popunjen!";
            }
        }
        public void validacija()
        {
            bool greska = false;
            for (int i = 0; i < 9; i++)
                for (int j = 0; j < 9; j++)
                {
                    String tmp = Convert.ToString(i + 1) + Convert.ToString(j + 1);
                    RichTextBox rchtxt = vratiTextBox(tmp[0], tmp[1]);
                    if (rchtxt.Enabled && rchtxt.Text != "")
                        if (rchtxt.Text != this.tabla.tabla[i][j].ToString())
                        {
                            rchtxt.BackColor = Color.OrangeRed;
                            greska = true;
                        }
                }
            if (greska)
            {
                this.stanjeStatusneLabele = labelStatus.Text;
                this.SudokuStatusStrip.BackColor = Color.OrangeRed;
                this.labelStatus.Text = "Sudoku nije ispravno popunjen!";
            }
            else
            {
                gotovaIgra = true;
                pocelaIgra = false;
                štoperica.Stop();
                this.SudokuStatusStrip.BackColor = Color.DeepSkyBlue;
                MessageBox.Show("Sudoku je uspješno ispunjen. Čestitke!");
                this.labelStatus.Text = "Sudoku uspješno ispunjen. Čestitke!";
                for (int i = 0; i < 9; i++)
                    for (int j = 0; j < 9; j++)
                    {
                        String tmp = Convert.ToString(i + 1) + Convert.ToString(j + 1);
                        RichTextBox rchtxt = vratiTextBox(tmp[0], tmp[1]);
                        rchtxt.ReadOnly = true;
                        rchtxt.BackColor = Color.LightSkyBlue;
                    }
                if (štoperica.Elapsed.Seconds < rekordi[4].Vrijeme)
                    spremiRekord();
            }
        }
        public void ocistiPlocu()
        {
            foreach (Panel p in this.panelGlavni.Controls)
                foreach (RichTextBox rt in p.Controls)
                {
                    rt.Enabled = true;
                    rt.ReadOnly = false;
                    rt.Text = "";
                }
        }
        public void vratiBoje()
        {
            foreach (Panel p in this.panelGlavni.Controls)
                foreach (RichTextBox rt in p.Controls)
                    if (rt.BackColor == Color.OrangeRed)
                    {
                        if (rt.Focused)
                            rt.BackColor = Color.LightSkyBlue;
                        else
                            rt.BackColor = Color.White;
                    }
            this.SudokuStatusStrip.BackColor = Color.DeepSkyBlue;
            labelStatus.Text = "Level: " + level + " - igra u toku.";
            validiran = false;
        }

        private void labelVrijeme_Click(object sender, EventArgs e)
        {
            pauziraj();
        }
    }
}
